<template>
  <div class="cusEngine" ref="cusEngine">
    <div class="operate_div" v-if="!isRead">
      <div class="one_operate" style="padding: 5px 0;box-sizing: border-box" @mousedown="addNode('ellipse',$event, {
        width: 130,
        height: 60
      }, '开始')">
        <div class="ellipse">
          <span style="color: #333333;font-size: 14px">开始</span>
        </div>
      </div>
      <div class="one_operate" @mousedown="addNode('rect',$event, {
        width: 130,
        height: 60
      }, '节点')">
        <canvas width="140" height="70" style="margin: 0 auto" id="rect"></canvas>
      </div>
      <div class="one_operate" @mousedown="addNode('diamond',$event, {
        width: 130,
        height: 60
      }, '条件')">
        <canvas width="140" height="70" style="margin: 0 auto" id="diamond"></canvas>
      </div>
      <div class="one_operate" style="padding: 5px 0;box-sizing: border-box" @mousedown="addNode('ellipse',$event, {
        width: 130,
        height: 60
      }, '结束')">
        <div class="ellipse">
          <span style="color: #333333;font-size: 14px">结束</span>
        </div>
      </div>
    </div>
    <div id="mountNode" :style="{ width: isRead ? '100%' : 'calc(100% - 150px)' }" ref="mountNode"></div>
    <div class="new_node" ref="newNode" v-if="addNewNode" :style="newNode">
      <canvas id="moveDiamond" v-if="isDiamond" width="newNode.width" :height="newNode.height"></canvas>
      <div class="moveTitle" v-else>{{moveTitle}}</div>
    </div>
    <div class="add_bg" v-show="add_bg"></div>
  </div>
</template>
<script>
import G6 from "@antv/g6";

export default {
  name: "cusEngine",
  data() {
    return {
      graph: null,
      nowId: null,
      isDiamond: false,
      moveTitle: '',
      graphZoom: 1,
      addNewNode: false,
      isRead: false,
      add_bg: false,
      // 点集
      nodes: [],
      // 边集
      edges: [],
      // 新节点的样式
      newNode: {},
      // 当前选择的连线的 ID
      theEdgeId: null,
      // 当前选择的节点的 ID
      theNodeId: null,
      // 是否是在添加线
      orAddEdge: false,
    }
  },
  props: {},
  watch: {},
  computed: {},
  worker: [],
  methods: {
    setNodes(data) {
      this.nodes = data
    },
    setEdgesAndNodes(data) {
      this.add_bg = false
      this.isRead = data.isRead
      // this.createEdge = data.createEdge
      this.edges = data.edges
      this.nodes = data.nodes
      this.nowId = data.maxId
      if (this.graph) {
        this.theEdgeId = null
        this.theNodeId = null
        this.graph.clear();
        this.graph.changeData({
          nodes: this.nodes,
          edges: this.edges
        }) // 渲染图
      }
    },
    setCanvas() {
      const cusEngineWidth = this.$refs.cusEngine.clientWidth
      const width =  this.isRead ? cusEngineWidth : cusEngineWidth - 150
      const height = this.$refs.mountNode.clientHeight
      this.graph = new G6.Graph({
        defaultNode: {
          size: 30, // 节点大小
          // ...                 // 节点的其他配置
          // 节点样式配置
          style: {
            fill: 'steelblue', // 节点填充色
            stroke: '#666', // 节点描边色
            lineWidth: 1 // 节点描边粗细
          },
          // 节点上的标签文本配置
          labelCfg: {
            // 节点上的标签文本样式配置
            style: {
              fill: '#fff' // 节点标签文字颜色
            }
          }
        },
        container: 'mountNode', // String | HTMLElement，必须，在 Step 1 中创建的容器 id 或容器本身
        width: width, // Number，必须，图的宽度
        height: height, // Number，必须，图的高度
        modes: this.isRead ? {
          default: ['drag-canvas', 'zoom-canvas']
        } :{
          default: [ 'brush-select', 'drag-canvas', 'zoom-canvas', {
            type: 'drag-node',
          }, {
            type: 'create-edge',
            trigger: 'click',
            key: 'alt',
            edgeConfig: {
              id: 'new1',
              style: {
                endArrow: true,
                lineWidth: 1,
                stroke: '#79ace8',
              },
              type: 'line',
            },
          },],
        },
        size: [100, 500]
      })
      this.graph.data({
        nodes: this.nodes,
        edges: this.edges
      })
      this.graph.render() // 渲染图
      this.graphZoom = this.graph.getZoom()
      if (!this.isRead) {
        this.graph.on('node:dragstart', evt => {})
        this.graph.on('node:dragend', evt => {
          let id =  evt.item._cfg.id
          const point = this.graph.getPointByClient(evt.clientX, evt.clientY);
          this.nodes.forEach(item => {
            if (item.id === id) {
              item.x = point.x
              item.y = point.y
            }
          })
          this.graph.refreshPositions()
        })
        // 点击连线
        this.graph.on('edge:click', evt => {
          this.editWindowShow = true
          this.editWindowType = 'edge'
          let data = {}
          let oldId = null
          let oldData = {}
          if ( this.theEdgeId === evt.item._cfg.id ) {
            return false
          }
          this.theEdgeId = evt.item._cfg.id
          this.edges.forEach(item => {
            if (item.style.lineWidth === 3) {
              item.style.lineWidth = 1
              oldId = item.id
              oldData = item
            }else if (item.id === evt.item._cfg.id) {
              item.style.lineWidth = 3
              data = item
            }
          })
          if (oldId) {
            this.graph.updateItem(oldId , oldData,true)
          }
          this.graph.updateItem(this.theEdgeId , data,true)
          if ( this.theNodeId ) {
            let nodeData = null
            this.nodes.forEach(item => {
              item.style.lineWidth = 1
              if (item.id ===  this.theNodeId ) {
                nodeData = item
              }
            })
            this.graph.updateItem(this.theNodeId , nodeData,true)
          }
          this.theNodeId = null
          const mData = {
            ...data,
            nodes: this.nodes,
            edges: this.edges,
          }
          this.$emit('editEdge', {
            ...data,
            nodes: this.nodes,
            edges: this.edges,
          })
        })
        this.graph.on('node:click', evt => {
          this.editWindowShow = true
          this.editWindowType = 'node'
          let data = {}
          let oldId = null
          let oldData = {}
          if ( this.orAddEdge ) {
            return false
          }else {
            if ( this.theNodeId === evt.item._cfg.id ) {
              return false
            }
            this.theNodeId = evt.item._cfg.id
            this.nodes.forEach(item => {
              if (item.style.lineWidth === 3) {
                item.style.lineWidth = 1
                oldId = item.id
                oldData = item
              }else if (item.id === evt.item._cfg.id) {
                item.style.lineWidth = 3
                data = item
              }
            })

            // 点击节点的时候，清除边选中的样式
            if ( this.theEdgeId ) {
              let nodeData = null
              this.edges.forEach(item => {
                item.style.lineWidth = 1
                if (item.id ===  this.theEdgeId ) {
                  nodeData = item
                }
              })
              this.graph.updateItem(this.theEdgeId , nodeData)
            }
            this.theEdgeId = null
            this.$emit('editNode', {
              nodes: this.nodes,
              edges: this.edges,
              theNodeId: this.theNodeId,
              editWindowType: 'node',
            })
          }

        })
        this.graph.on('dragend', evt => {
          const nodes = this.graph.getNodes()
          const eges = this.graph.getNodes();
          this.$emit('moveOneStep',{
            nodes: this.nodes,
            edges: this.edges,
          })
        })
        this.graph.on('aftercreateedge', (e) => {
          this.orAddEdge = true
          let id = 1
          if ( this.edges.length !== 0) {
            id = Number(this.edges[ this.edges.length - 1 ].id.replace(/[^0-9]/g,"")) + 1
          }
          this.edges.push({
            id: `edge${id}`,
            source: e.edge._cfg.source._cfg.id,
            target: e.edge._cfg.target._cfg.id,
            style: {
              endArrow: true,
              lineWidth: 1,
              stroke: '#79ace8',
            },
            labelCfg: {
              style: {
                lineWidth: 3,
                stroke: '#ffffff'
              }
            },
            type: 'polyline',
            label: 'polyline',
          })
          this.graph.addItem('edge', {
            id: `edge${id}`,
            source: e.edge._cfg.source._cfg.id,
            target: e.edge._cfg.target._cfg.id,
            style: {
              endArrow: true,
              lineWidth: 1,
              stroke: '#79ace8',
            },
            labelCfg: {
              style: {
                lineWidth: 3,
                stroke: '#ffffff'
              }
            },
            type: 'polyline',
            label: 'polyline',
          });
          const aIndex = this.nodes.findIndex(item => item.id === e.edge._cfg.source._cfg.id)
          this.nodes[aIndex].style.lineWidth = 1
          this.graph.updateItem(e.edge._cfg.source._cfg.id , this.nodes[aIndex])
          this.graph.clearItemStates(e.edge._cfg.source._cfg.id);
          this.graph.clearItemStates(e.edge._cfg.target._cfg.id);
          this.$nextTick(() => {
            const item = this.graph.findById('new1')
            this.graph.removeItem(item)
          })
          this.$emit('addEdge', {
            nodes: this.nodes,
            edges: this.edges,
            id: `edge${id}`
          })
          this.add_bg = true
        });
        this.graph.on('wheel', (e) => {
          this.graphZoom = this.graph.getZoom()
        });
      }
    },
    handleKeyup(event) {
      // 按删除键
      if (event.key === 'Alt') {
        this.orAddEdge = true
      }
      if (event.key === 'Escape') {
        this.edges.map(item => {
          item.style.lineWidth = 1
        })
        this.nodes.map(item => {
          item.style.lineWidth = 1
        })
        if (this.theEdgeId) {
          const edge =  this.edges.find(item => item.id === this.theEdgeId)
          this.graph.updateItem(this.theEdgeId,edge)
        }
        if (this.theNodeId) {
          const nodes =  this.nodes.find(item => item.id === this.theNodeId)
          this.graph.updateItem(this.theNodeId,nodes)
        }
        this.theEdgeId = null
        this.theNodeId = null
      }
    },
    moveNode(e,type) {
      this.newNode.left = `${e.clientX - ( type.width * this.graphZoom / 2 )}px`
      this.newNode.top = `${e.clientY - ( type.height * this.graphZoom / 2 )}px`
    },
    addNode(type,e, style, moveTitle) {
      this.addNewNode = true
      this.isDiamond = false
      let anchorPoints = []
      let aStyle = {}
      this.moveTitle = moveTitle
      if ( type === 'circle' || type === 'ellipse' ) {
        aStyle = {
          borderRadius: `50%`
        }
      }
      if ( type === 'diamond') {
        this.isDiamond = true
        const mim = style.width * style.width * 2
        const scale =  (style.width * style.width)
        aStyle = {
          'border': "none",
          "background": 'transparent'
        }
      }
      if ( type === 'rect' ) {
        anchorPoints = [
          [0, 0],
          [0.5, 0],
          [1, 0],
          [1, 0.5],
          [1, 1],
          [0.5, 1],
          [0, 1],
          [0, 0.5],
        ]
      }else {
        anchorPoints = [
          [0.5, 0],
          [1, 0.5],
          [0.5, 1],
          [0, 0.5],
        ]
      }
      this.newNode = {
        left: `${e.clientX - ( style.width * this.graphZoom / 2 )}px`,
        top: `${e.clientY - ( style.height * this.graphZoom / 2 )}px`,
        width: `${style.width * this.graphZoom}px`,
        height: `${style.height * this.graphZoom}px`,
        ...aStyle
      }

      if (this.isDiamond) {
        this.$nextTick(() => {
          this.setMoveDiamond()
        })
      }
      window.onmousemove = (e) => this.moveNode(e,style)
      window.onmouseup = (e) => {
        if (!this.addNewNode) return
        let top = Number( this.$refs.newNode.style.top.split('px')[0] )
        let left = Number( this.$refs.newNode.style.left.split('px')[0] )
        top += (this.$refs.newNode.clientHeight / 2)
        left += (this.$refs.newNode.clientWidth / 2)
        const point = this.graph.getPointByClient(left, top);
        window.onmousemove = (e) => null
        let id = this.nowId + 1
        this.nodes.push({
          id: id, // String，该节点存在则必须，节点的唯一标识
          size: [ style.width, style.height ],
          type: type, // 矩形节点
          label: moveTitle, // 矩形节点框内的文字
          // 矩形节点框样式
          style: {
            fill: '#ffffff',
            stroke: '#79ace8',
            lineWidth: 1,
            radius: 0
          },
          x: point.x, // Number，可选，节点位置的 x 值
          y: point.y, // Number，可选，节点位置的 y 值
          anchorPoints: anchorPoints,
          labelCfg: {
            style: {
              fontSize: 14,
              fill: '#000000'
            }
          },
        })
        this.$emit('addOneStep', {
          editWindowShow: true,
          editWindowType: 'node',
          stepId: id,
          nodes: this.nodes,
          edges: this.edges,
        })
        this.graph.addItem('node', {
          id: id, // String，该节点存在则必须，节点的唯一标识
          size: [ style.width, style.height ],
          type: type, // 矩形节点
          label: moveTitle, // 矩形节点框内的文字
          // 矩形节点框样式
          style: {
            fill: '#ffffff',
            stroke: '#79ace8',
            lineWidth: 1,
            radius: 0
          },
          x: point.x, // Number，可选，节点位置的 x 值
          y: point.y, // Number，可选，节点位置的 y 值
          anchorPoints: anchorPoints,
          labelCfg: {
            style: {
              fontSize: 14,
              fill: '#000000'
            }
          },
        })
        // this.graph.render() // 渲染图
        this.addNewNode = false
        this.add_bg = true
        this.newNode = {}
        this.isDiamond = false
      }
    },
    setCircle() {
      const c = document.getElementById("circle");
      const ctx = c.getContext("2d");
      ctx.beginPath();
      ctx.arc(55,55,50,0,2*Math.PI);
      ctx.font="14px Arial";
      ctx.textAlign="center";
      ctx.strokeStyle="#79ace8";
      ctx.lineWidth=3;
      ctx.fillText("节点",55,60);
      ctx.stroke();
    },
    setRect() {
      const c = document.getElementById("rect");
      const ctx = c.getContext("2d");
      ctx.strokeStyle= '#79ace8';
      ctx.lineWidth=3;
      ctx.fillStyle = '#ffffff'
      ctx.fillRect(5,5,130,60);
      ctx.strokeRect(5,5,130,60);
      ctx.fillStyle = '#000000'
      ctx.font="14px Arial";
      ctx.textAlign="center";
      ctx.fillText("节点",70,40);
    },
    setDiamond() {
      const c = document.getElementById("diamond");
      const ctx = c.getContext("2d");
      ctx.beginPath();
      ctx.moveTo(5, 35);
      ctx.lineTo(70, 5);
      ctx.lineTo(135, 35);
      ctx.lineTo(70, 65);
      ctx.fillStyle = '#ffffff'
      ctx.lineWidth=3;
      ctx.closePath();
      ctx.strokeStyle = "#79ace8";
      ctx.fill();
      ctx.font="14px Arial";
      ctx.textAlign="center";
      ctx.fillStyle = '#000000'
      ctx.fillText("条件",70,40);
      ctx.stroke();
    },
    setMoveDiamond() {
      const c = document.getElementById("moveDiamond");
      const ctx = c.getContext("2d");
      ctx.beginPath();
      ctx.moveTo(3, 30);
      ctx.lineTo(65, 3);
      ctx.lineTo(127, 30);
      ctx.lineTo(65, 60);
      ctx.fillStyle = '#ffffff'
      ctx.lineWidth=3;
      ctx.closePath();
      ctx.strokeStyle = "#79ace8";
      ctx.fill();
      ctx.font="14px Arial";
      ctx.textAlign="center";
      ctx.fillStyle = '#000000'
      ctx.fillText("节点",65,40);
      ctx.stroke();
    }
  },
  mounted () {
    this.$nextTick(() => {
      const currentEmployee = window.sessionStorage.getItem('currentEmployee')
      this.setRect()
      this.setDiamond()
      this.setCanvas()
      window.addEventListener('keydown',this.handleKeyup)
      window.addEventListener('keyup',(e) => {
        this.orAddEdge = false
      })
      window.onresize = () => {
        const width = this.$refs.mountNode.clientWidth
        const height = this.$refs.mountNode.clientHeight
        this.graph.changeSize(width, height);
      }
    })
  },

}
</script>
<style scoped lang="scss">
.cusEngine {
  width: 100%;
  height: 100%;
  display: flex;
  display: -moz-flex;
  display: -webkit-flex;

  .operate_div {
    width: 150px;
    flex-basis: 150px;
    flex-shrink: 0;
    height: 100%;
    box-sizing: border-box;
    padding: 5px;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    background: #f8f6f6;
    align-content: flex-start;
    justify-content: flex-start;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);

    .one_operate {
      width: 100%;
      text-align: center;
      height: auto;
      cursor: pointer;
      margin-bottom: 10px;
      border-radius: 5px;
      transition: color 0.2s, background 0.2s;

      .iconfont {
        font-size: 40px;
        box-sizing: border-box;
        color: #706d6d;

        font-weight: bold;
      }

      &:hover {
        background: #b5dbec;
      }

      .diamond {
        width: 80px;
        height: 80px;
        border: 2px solid #79ace8;
        background-color: #ffffff;
        margin: 0 auto;
      }
    }
  }
}
#mountNode {
  width: calc(100% - 150px);
  height: 100%;
  overflow: hidden;
  //background: #f5f3f3;
  //background-image:
  //    linear-gradient(45deg, #dcdcdc 25%, transparent 0, transparent 75%, #dcdcdc 0),
  //    linear-gradient(45deg, #dcdcdc 25%, transparent 0, transparent 75%, #dcdcdc 0);
  background-position: 0 0, 4px 4px;
  background-size: 8px 8px;
}
.new_node {
  position: fixed;

  z-index: 20;
  border: 2px solid #79ace8;
  background-color: #ffffff;

  .moveTitle {
    width: 100%;
    height: 100%;
    display: flex;
    display: -webkit-flex;
    display: -moz-flex;
    align-items: center;
    justify-content: center;
    display: -ms-flex;
  }
}

.ellipse {
  width: 140px;
  margin: 0 auto;
  box-sizing:border-box;
  display: flex;
  display: -webkit-flex;
  display: -moz-flex;
  align-items: center;
  justify-content: center;
  height: 60px;
  border-radius: 50%;
  border: 3px solid #79ace8;
  background: #ffffff;
}

.add_bg {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  background: rgba(0,0,0,0.3);
}
</style>
